class Student:
    def __init__(self, name, age, score):
        self.name = name  # 实例属性
        self.age = age
        self.score = score

    def introduce(self):
        print(f"我是{self.name}，今年{self.age}岁，分数{self.score}")

    def is_pass(self):
        return self.score >= 60


# 创建一个学生对象
stu1 = Student("Alice", 20, 85)
stu1.introduce()  # 输出：我是Alice，今年20岁，分数85
print(stu1.is_pass())  # True


class Student:
    def __init__(self, name):
        self.name = name  # 公开属性 public
        self._nickname = name  # 受保护属性 protected
        self.__realname = name  # 私有属性 private


# 创建实例
stu = Student("小明")

# 公开属性，直接访问
print(stu.name)  # 小明
stu.name = "小红"
print(stu.name)  # 小红

# 受保护属性（实际能访问，但约定不要在类外直接访问）
print(stu._nickname)  # 小明
stu._nickname = "小亮"
print(stu._nickname)  # 小亮

# 私有属性，不能直接访问
# print(stu.__realname)  # AttributeError，不能直接访问

# 可以通过特殊方式访问私有属性（不推荐）
print(stu._Student__realname)  # 小明


class Demo:
    def __init__(self, value):
        self._value = value  # 习惯上受保护（单下划线）

    # 定义 value 属性的 getter 方法
    @property
    def value(self):
        return self._value

    # 定义 value 属性的 setter 方法
    @value.setter
    def value(self, new_value):
        # 检查 new_value 是否为 int 类型且值为非负
        if isinstance(new_value, int) and new_value >= 0:
            self._value = new_value
        else:
            raise ValueError("value 必须为非负整数")


# 创建实例
d = Demo(5)
print(d.value)  # 相当于 d.value()，自动调用@property修饰的方法，输出 5
d.value = 10  # 相当于 d.value(10)，自动调用 setter
print(d.value)  # 相当于 d.value()，自动调用@property修饰的方法，输出 10


# d.value = -3  # 会抛出 ValueError
class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def area(self):
        return 3.14 * self._radius**2


c = Circle(2)
print(c.area)  # 12.56


# c.area = 10   # 报错：只读属性
class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        # 父类只定义接口/默认实现，一般由子类重写
        raise NotImplementedError("子类必须实现speak方法")


class Dog(Animal):
    def speak(self):
        return f"{self.name}: 汪汪！"


class Cat(Animal):
    def speak(self):
        return f"{self.name}: 喵喵！"


animal = Animal("动物")
dog = Dog("小黑")
cat = Cat("小花")
print(dog.speak())  # 小黑: 汪汪！
print(cat.speak())  # 小花: 喵喵！
print(isinstance(dog, Animal))  # True
print(animal.name)


class A:
    def foo(self):
        print("A.foo")


class B:
    def bar(self):
        print("B.bar")


class C(A, B):
    pass


c = C()
c.foo()  # 输出: A.foo
c.bar()  # 输出: B.bar
print(C.__mro__)


# (<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
class Demo:
    def __new__(cls, *args, **kwargs):
        print(f"__new__ called: 分配对象空间，cls={cls}")
        instance = super().__new__(cls)  # 实际分配空间并返回实例
        return instance

    def __init__(self, value):
        print(f"__init__ called: 初始化对象，设置 value={value}")
        self.value = value


print("创建 Demo 对象：")
d = Demo(42)
print(f"对象属性 value = {d.value}")


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Vector({self.x}, {self.y})"

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __sub__(self, other):
        return Vector(self.x - other.x, self.y - other.y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __lt__(self, other):
        return self.magnitude() < other.magnitude()

    def __len__(self):
        return 2  # 总是2D向量

    def __getitem__(self, index):
        if index == 0:
            return self.x
        elif index == 1:
            return self.y
        else:
            raise IndexError("Vector index out of range")

    def magnitude(self):
        return (self.x**2 + self.y**2) ** 0.5


# 使用示例
v1 = Vector(2, 3)
v2 = Vector(4, 5)

print(v1)  # Vector(2, 3)
print(v1 + v2)  # Vector(6, 8)
print(v1 * 3)  # Vector(6, 9)
print(v1 == Vector(2, 3))  # True
print(v1[0])  # 2
print(v1.magnitude())  # 3.605551275463989


# 定义一个学生类
class Student:
    # 定义学校名称，为类属性
    school_name = "Python University"
    # 记录学生总数，为类属性
    students_count = 0

    # 构造方法，初始化学生对象
    def __init__(self, name, grade):
        # 赋值学生姓名
        self.name = name
        # 赋值学生年级
        self.grade = grade
        # 创建新学生对象时，学生总数加1
        Student.students_count += 1

    # 实例方法：获取学生信息
    def get_info(self):
        # 返回学生的姓名和成绩信息
        return f"{self.name} - Grade {self.grade}"

    # 类方法：获取学校信息
    @classmethod
    def get_school_info(cls):
        # 返回学校名称和学生总数
        return f"School: {cls.school_name}, Students: {cls.students_count}"

    # 工厂方法：通过字符串创建学生对象
    @classmethod
    def create_from_string(cls, student_str):
        # 从字符串中分割出姓名和年级
        name, grade = student_str.split(",")
        # 去除空格并将年级转换为整数后，创建学生对象
        return cls(name.strip(), int(grade.strip()))

    # 静态方法：判断成绩及格与否
    @staticmethod
    def is_passing_grade(grade):
        # 成绩大于等于60为及格
        return grade >= 60

    # 静态方法：计算成绩平均值
    @staticmethod
    def calculate_average(grades):
        # 如果成绩列表非空，返回平均值，否则返回0
        return sum(grades) / len(grades) if grades else 0


# 创建两个学生对象，分别为Alice和Bob
student1 = Student("Alice", 85)
student2 = Student("Bob", 92)

# 调用实例方法，输出student1的信息
print(student1.get_info())  # Alice - Grade 85

# 调用类方法，输出学校信息和学生总数
print(Student.get_school_info())  # School: Python University, Students: 2

# 使用工厂方法从字符串创建学生对象
student3 = Student.create_from_string("Charlie, 78")
# 输出student3的信息
print(student3.get_info())  # Charlie - Grade 78

# 调用静态方法，判断75是否及格
print(Student.is_passing_grade(75))  # True
# 调用静态方法，计算平均成绩
print(Student.calculate_average([85, 92, 78]))  # 85.0


class FileOpener:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        print("打开文件")
        self.file = open(self.filename, self.mode)
        return self.file

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("关闭文件")
        if self.file:
            self.file.close()
        # 可以选择是否处理异常（True防止异常继续向上传播，False/不返回则传播）


# 使用自定义上下文管理器
with FileOpener("demo.txt", "w") as f:
    f.write("hello, context manager!")
# 导入抽象基类模块
from abc import ABC, abstractmethod

# 导入当前日期时间模块
from datetime import datetime

# 导入类型提示列表
from typing import List


# 定义员工抽象基类
class Employee(ABC):
    # """员工抽象基类"""

    # 初始化员工信息
    def __init__(self, name: str, employee_id: str, salary: float):
        # 员工姓名
        self.name = name
        # 员工编号
        self.employee_id = employee_id
        # 员工工资
        self.salary = salary
        # 入职日期设为当前时间
        self.hire_date = datetime.now()

    # 抽象方法，计算奖金
    @abstractmethod
    def calculate_bonus(self) -> float:
        # """计算奖金"""
        pass

    # 抽象方法，获取员工角色
    @abstractmethod
    def get_role(self) -> str:
        # """获取角色"""
        pass

    # 获取员工基本信息字符串
    def get_info(self) -> str:
        return f"{self.name}（{self.employee_id}） - {self.get_role()}"


# 定义经理类，继承自Employee
class Manager(Employee):
    # 初始化经理相关信息
    def __init__(self, name: str, employee_id: str, salary: float, department: str):
        # 调用父类构造器
        super().__init__(name, employee_id, salary)
        # 部门名称
        self.department = department
        # 团队成员列表
        self.team: List[Employee] = []

    # 计算经理奖金（工资的30%）
    def calculate_bonus(self) -> float:
        return self.salary * 0.3

    # 获取经理的角色名
    def get_role(self) -> str:
        return f"{self.department}经理"

    # 添加团队成员
    def add_team_member(self, employee: Employee):
        self.team.append(employee)

    # 获取团队人数
    def get_team_size(self) -> int:
        return len(self.team)


# 定义开发工程师类，继承自Employee
class Developer(Employee):
    # 初始化开发工程师信息
    def __init__(
        self, name: str, employee_id: str, salary: float, programming_language: str
    ):
        # 调用父类构造器
        super().__init__(name, employee_id, salary)
        # 擅长的编程语言
        self.programming_language = programming_language

    # 计算开发工程师奖金（工资的20%）
    def calculate_bonus(self) -> float:
        return self.salary * 0.2

    # 获取工程师的角色名
    def get_role(self) -> str:
        return f"{self.programming_language}开发工程师"


# 定义设计师类，继承自Employee
class Designer(Employee):
    # 初始化设计师信息
    def __init__(self, name: str, employee_id: str, salary: float, design_tool: str):
        # 调用父类构造器
        super().__init__(name, employee_id, salary)
        # 擅长的设计工具
        self.design_tool = design_tool

    # 计算设计师奖金（工资的15%）
    def calculate_bonus(self) -> float:
        return self.salary * 0.15

    # 获取设计师的角色名
    def get_role(self) -> str:
        return f"{self.design_tool}设计师"


# 定义公司类
class Company:
    # 初始化公司信息
    def __init__(self, name: str):
        # 公司名称
        self.name = name
        # 员工列表
        self.employees: List[Employee] = []

    # 雇佣新员工
    def hire(self, employee: Employee):
        self.employees.append(employee)
        # 打印雇佣信息
        print(f"已雇佣: {employee.get_info()}")

    # 计算公司总薪酬（基本工资+奖金）
    def calculate_total_payroll(self) -> float:
        # 所有员工工资之和
        total = sum(emp.salary for emp in self.employees)
        # 所有员工奖金之和
        total_bonus = sum(emp.calculate_bonus() for emp in self.employees)
        return total + total_bonus

    # 输出员工列表及奖金
    def list_employees(self):
        print(f"\n{self.name} 员工列表：")
        for employee in self.employees:
            print(f"  - {employee.get_info()}")
            print(f"    奖金: ￥{employee.calculate_bonus():.2f}")


# 使用完整的面向对象系统

# 创建公司对象
company = Company("科技公司")

# 创建经理对象
manager = Manager("王小明", "M001", 80000, "工程部")
# 创建开发工程师对象1
dev1 = Developer("李雷", "D001", 70000, "Python")
# 创建开发工程师对象2
dev2 = Developer("韩梅梅", "D002", 75000, "JavaScript")
# 创建设计师对象
designer = Designer("张伟", "DS001", 65000, "Figma")

# 构建经理的团队，添加开发与设计成员
manager.add_team_member(dev1)
manager.add_team_member(dev2)
manager.add_team_member(designer)

# 公司雇佣所有员工
company.hire(manager)
company.hire(dev1)
company.hire(dev2)
company.hire(designer)

# 输出公司员工信息
company.list_employees()
# 输出公司总薪酬
print(f"\n总薪酬: ￥{company.calculate_total_payroll():.2f}")
# 输出经理的团队人数
print(f"经理团队人数: {manager.get_team_size()}")
